home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / freeWAIS-sf-1.1 / ir / sersrch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-13  |  40.7 KB  |  1,399 lines

  1.  
  2. /* Copyright (c) CNIDR (Work in progress) */
  3.  
  4. /* WIDE AREA INFORMATION SERVER SOFTWARE
  5.    No guarantees or restrictions.  See the readme file for the full standard
  6.    disclaimer.    
  7.    Brewster@think.com
  8. */
  9.  
  10.  
  11. /* implements the search part of irext.h 
  12.    (search_word and finished_search_word)
  13.    -brewster
  14.  
  15. Split from irsearch.c
  16.  
  17.    5/31/91 Added scale_scores.  Fixed document_score_array to long.
  18.    7/8/91 Removed scale_scores, handled in search_word with doc_id > 0.
  19.    2/4/92 Made document_score_array a double.
  20.  
  21.    - Jonny G
  22.  * $Log: sersrch.c,v $
  23.  * Revision 1.54  1994/12/13  17:03:58  pfeifer
  24.  * *** empty log message ***
  25.  *
  26.  * Revision 1.53  1994/11/14  15:58:17  pfeifer
  27.  * Patch by Archie Warnoc in c.i.w (must be made size dependent?)
  28.  *
  29.  * Revision 1.52  1994/09/06  16:53:48  pfeifer
  30.  * Syn cache patch
  31.  *
  32.  * Revision 1.51  1994/08/05  09:46:46  pfeifer
  33.  * No more 'MAXINT redefined' complaints.
  34.  *
  35.  * Revision 1.50  1994/08/05  07:12:38  pfeifer
  36.  * Release beta 04
  37.  *
  38.  * Revision 1.49  1994/07/13  07:52:36  huynh1
  39.  * Uli
  40.  *
  41.  * Revision 1.48  1994/05/27  09:13:21  huynh1
  42.  * boolean code updated. beta
  43.  *
  44.  * Revision 1.47  1994/05/26  14:33:57  huynh1
  45.  * search_word updated (read_weight_from_stream).
  46.  * beta.
  47.  *
  48.  * Revision 1.46  1994/05/20  12:49:58  pfeifer
  49.  * beta
  50.  *
  51.  * Revision 1.45  1994/05/19  12:44:39  huynh1
  52.  * search_word updated.
  53.  *
  54.  * Revision 1.44  1994/05/18  17:28:13  huynh1
  55.  * new term weighting
  56.  * higher retrieval quality.
  57.  *
  58.  * Revision 1.40  1994/04/28  16:28:01  huynh1
  59.  * stemming
  60.  *
  61.  * Revision 1.39  1994/04/06  23:52:04  huynh1
  62.  * 08, autoconf, Uli
  63.  *
  64.  * Revision 1.38  1994/03/23  13:11:07  pfeifer
  65.  * removed include iso.h
  66.  *
  67.  * Revision 1.37  1994/03/08  20:46:12  huynh1
  68.  * Patchlevel 04
  69.  *
  70.  * Revision 1.36  1994/02/14  10:33:04  huynh1
  71.  * new code for field concept added.
  72.  *
  73.  * Revision 1.36  1993/12/08  17:38:00  huynh1
  74.  * bug by mixing literal and nested boolean corrected!
  75.  *
  76.  * Revision 1.10  1993/10/13  14:14:20  huynh1
  77.  * new code added for encapsulated boolean queries and
  78.  * modified literal search
  79.  *
  80.  * Revision 1.3  1993/07/13  08:19:56  pfeifer
  81.  * Sicherung vor Aenderungen Tung
  82.  *
  83.  * Revision 1.1  1993/02/16  15:05:35  freewais
  84.  * Initial revision
  85.  *
  86.  * Revision 1.24  92/04/28  16:56:54  morris
  87.  * added boolean to serial engine
  88.  * 
  89.  * Revision 1.23  92/03/15  10:15:18  jonathan
  90.  * Added Simon Spero's ASSIGN replacement for read_bytes.
  91.  * 
  92.  * Revision 1.22  92/03/05  07:09:54  shen
  93.  * add two more dummy arguments to call to init_search_engine
  94.  * 
  95.  * Revision 1.21  92/02/12  17:29:52  jonathan
  96.  * Conditionalized inclusion of object code.
  97.  * 
  98.  * Revision 1.20  92/02/12  13:40:06  jonathan
  99.  * Added "$Log" so RCS will put the log message in the header
  100.  * 
  101. */
  102.  
  103. #include "cutil.h"
  104. #include "irfiles.h"
  105. #ifdef BIO
  106. #include "irtfiles.h" /* dgg, for wordDelimiter */
  107. #endif
  108. #include "irsearch.h"
  109. #include "irext.h"
  110. #include "byte_order.h"
  111. /* #include <string.h> */
  112. #include <ctype.h>
  113.  
  114. #include <math.h>
  115.  
  116. #ifdef MAXINT
  117. #undef MAXINT
  118. #endif
  119. #define MAXINT (unsigned long)2^(sizeof(long)*8-1)
  120. #define VALUE 1000000L
  121. /* francois */
  122. #include "stemmer.h"   
  123.  
  124. /* tung, 10/93 */
  125. #ifdef NESTED_BOOLEANS
  126. #include "boolean_op.h"
  127. #endif
  128. /* tung, 10/93 */
  129.  
  130. #ifdef FIELDS /* tung, 1/94 */
  131. #include "field_search.h"
  132. #endif
  133.  
  134. #ifdef NEW_WEIGHT /* tung, 5/94 */
  135. #include "weight.h"
  136. #endif
  137.  
  138. #ifdef BOOL
  139. #include "obj.h"
  140. #include "irparse.h"
  141. object* currentQuery = NULL; /* kludge until irext goes away */
  142. #endif /* def BOOL */
  143.  
  144. /* weighting for relevant document terms - 
  145.    this may become a parameter to the query.
  146. */
  147.  
  148. #define RF_WEIGHTING 0.1
  149.  
  150. /* ==================================
  151.  * ===  Initialization Functions  ===
  152.  * ==================================*/
  153.  
  154.  
  155. long init_search_engine(file, initialize, for_search, cm_mem_percent, 
  156. text_size, grow_percent)
  157.   char* file;
  158.   boolean initialize;
  159.   boolean for_search;
  160.   long cm_mem_percent;  /* unused */
  161.   long text_size;     /* unused */
  162.   long grow_percent;  /* unused */
  163. {
  164.   static boolean inited = false;
  165.  
  166.   if (inited == false)
  167.    { 
  168. #ifdef BOOL
  169.      initObj();
  170.      initBool();
  171. #endif
  172.      inited = true;
  173.    }
  174.  
  175.   return(0);
  176. }
  177.  
  178. long finished_search_engine()
  179. {
  180. #ifdef CACHE_SYN
  181.   /* clean up shared memory segments */
  182.   if (cacheSynId) {
  183.     int i;
  184.     char *pcs;
  185.     t_cacheSyn *syn_Cache, *cs;
  186.     if ((syn_Cache = (t_cacheSyn *) shmat (cacheSynId, 0, 0)) != 
  187.     ((t_cacheSyn *)-1)) {
  188.       pcs = (char *) syn_Cache;
  189.       for (i = 0, cs = (t_cacheSyn *) pcs; i < MAX_SYN_CACHE && cs->id; 
  190.        i++, pcs += sizeof(t_cacheSyn), cs = (t_cacheSyn *) pcs)
  191.     if (shmctl(cs->id, IPC_RMID, (t_cacheSyn *)0) < 0)
  192.       waislog (WLOG_HIGH, WLOG_WARNING, "Error detatching shared memory segment (id=%d)", cs->id);
  193.       if (shmctl(cacheSynId, IPC_RMID, (t_cacheSyn *)0) < 0)
  194.     waislog (WLOG_HIGH, WLOG_WARNING, "Error detatching shared memory segment (id=%d)", cacheSynId);
  195.     }
  196.   }
  197. #endif
  198.   return(0);
  199. }
  200.  
  201.  
  202. /*
  203.  *  ext_open_database: see irext.h
  204.  */
  205.  
  206. long ext_open_database (db, initialize, for_search)
  207.      database *db;
  208.      boolean initialize;
  209.      boolean for_search;
  210. { /* this has to deal with the .inv file */
  211.   char file[MAX_FILE_NAME_LEN];
  212.  
  213.   if(initialize) /* make a new one */
  214.     db->index_stream = s_fopen(index_filename(file, db), "w+b");
  215.   else if(for_search) /* just search */
  216.     db->index_stream = s_fopen(index_filename(file, db), "rb");
  217.   else /* write to an existing db */
  218.     db->index_stream = s_fopen(index_filename(file, db), "r+b");
  219.  
  220.   if (db->index_stream == NULL) {
  221.     waislog(WLOG_HIGH, WLOG_ERROR,"2can't open the inverted index file %s\n", 
  222.         file);
  223.     disposeDatabase(db);
  224.     return(1);
  225.   }
  226.   return(0);
  227. }
  228.   
  229.  
  230.  
  231. /*
  232.  *  ext_close_database: see irext.h
  233.  */
  234.  
  235. long ext_close_database (db)
  236.      database *db;
  237. {
  238.   return(0);
  239. }
  240.  
  241. char *database_file(database_name)
  242.      char *database_name;
  243. {
  244.   return(database_name);
  245. }
  246.   
  247. /*===========================*
  248.  *===  Setting Paramters  ===*
  249.  *===========================*/
  250.  
  251. long max_hit_retrieved = 0;
  252. char **srcs = NULL;
  253.  
  254. long set_query_parameter (mask, parameters)
  255.      long mask;
  256.      query_parameter_type * parameters;
  257. {
  258.   switch (mask)
  259.     {
  260.     case SET_MAX_RETRIEVED_MASK:
  261.       max_hit_retrieved = parameters->max_hit_retrieved;
  262.       return(0);
  263.       break;
  264.     case SET_SELECT_SOURCE:
  265.       if(NULL != srcs){
  266.     if(NULL != srcs[0])
  267.       s_free(srcs[0]);
  268.     s_free(srcs);
  269.       }
  270.       srcs = parameters->srcs;
  271.       break;
  272.     default:
  273.       return(-1);
  274.       break;
  275.     }
  276.   return(0);
  277. }
  278.  
  279. /*==============================*
  280.  *===  Document Score Array  ===*
  281.  *==============================*/
  282.  
  283. double *document_score_array = NULL;
  284. long document_score_array_len = 0;
  285. #ifdef NESTED_BOOLEANS /* tung, 1/94 */
  286. double *NumPart_score_array = NULL;
  287. #else
  288. #ifdef BOOLEANS
  289. double *prev_score_array = NULL;                    /* 12/91 GS TLG */
  290. #endif
  291. #endif
  292.  
  293. #ifdef NESTED_BOOLEANS
  294. /* tung, 10/93 */
  295. search_result_struct *search_result_array = NULL;
  296. long operand_id = 0;
  297.  
  298. static void clear_search_result_array _AP((long* number_of_elements));
  299. static void clear_search_result_array(number_of_elements)
  300.      long* number_of_elements;
  301. {
  302.   long count;
  303.   
  304.   if(*number_of_elements > 1 && search_result_array != NULL) {
  305.     for(count=0; count < *number_of_elements; count++) {
  306.       if(search_result_array[count].doc_ids_array != NULL) 
  307.         s_free(search_result_array[count].doc_ids_array);
  308.     }
  309.     s_free(search_result_array);
  310.   }
  311.   *number_of_elements = 1;
  312. }
  313.  
  314. static void make_search_result_array _AP((long length));
  315. static void make_search_result_array(length)
  316.      long length;
  317. {
  318.   if(search_result_array == NULL) {
  319.     search_result_array = 
  320.       (search_result_struct *)
  321.         s_malloc((size_t)(length * sizeof(search_result_struct)));
  322.     operand_id = 0;
  323.   }
  324. }
  325.  
  326. static boolean make_doc_ids_array _AP((long pos, long length));
  327. static boolean make_doc_ids_array(pos, length)
  328.      long pos;
  329.      long length;
  330. {
  331.   /* if(search_result_array[pos].doc_ids_array == NULL) */
  332.   search_result_array[pos].doc_ids_array =
  333.     (doc_descr_struct *)
  334.       s_malloc((size_t)(sizeof(doc_descr_struct) * length));
  335.   if(search_result_array[pos].doc_ids_array == NULL) {
  336.     waislog(WLOG_HIGH, WLOG_ERROR, "Out of memory");
  337.     return(false);
  338.   }
  339.   return(true);
  340. }
  341. /* tung, 10/93 */
  342. #endif
  343.  
  344. /* make_document_score_array insures that the document_score_array
  345.    array is long enough, if not it makes it long enough */
  346. static void make_document_score_array _AP((long length ));
  347. static void make_document_score_array(length)
  348. long length;
  349. {
  350.   if(length <= document_score_array_len)
  351.     return;
  352.   /* we have to make a new one.  free the old one first (if any) */
  353.   if(document_score_array != 0){
  354.     s_free(document_score_array);
  355. #ifdef NESTED_BOOLEANS /* tung, 1/94 */
  356.     s_free(NumPart_score_array);
  357. #else
  358. #ifdef BOOLEANS
  359.     s_free(prev_score_array);                    /* 12/91 GS TLG */
  360. #endif
  361. #endif
  362.   }
  363.   document_score_array = (double*)s_malloc((size_t)(length * sizeof(double)));
  364. #ifdef NESTED_BOOLEANS /* tung, 1/94 */
  365.   NumPart_score_array   = (double*)s_malloc((size_t)(length * sizeof(double)));
  366.   memset(NumPart_score_array, 0,
  367.      document_score_array_len * sizeof(double));
  368. #else
  369. #ifdef BOOLEANS
  370.   prev_score_array   = (double*)s_malloc((size_t)(length * sizeof(double)));  /* 12/91 GS TLG */
  371. #endif
  372. #endif
  373.   document_score_array_len = length;
  374. }
  375.  
  376. static void destroy_document_score_array _AP((void));
  377. static void destroy_document_score_array()
  378. {
  379.   s_free(document_score_array);
  380. #ifdef NESTED_BOOLEANS /* tung, 1/94 */
  381.   s_free(NumPart_score_array);
  382. #else
  383. #ifdef BOOLEANS
  384.   s_free(prev_score_array);                    /* 12/91 GS TLG */
  385. #endif
  386. #endif
  387.   document_score_array_len = 0;
  388. }
  389.     
  390. void clear_document_score_array()
  391.      /* side effects the document_score_array. */
  392.   memset(document_score_array, 0, 
  393.      document_score_array_len * sizeof(double));
  394. #ifdef NESTED_BOOLEANS /* tung, 1/94 */
  395.   memset(NumPart_score_array, 0,
  396.          document_score_array_len * sizeof(double));
  397. #else
  398. #ifdef BOOLEANS
  399.   memset(prev_score_array, 0,                    /* 12/91 GS TLG */
  400.          document_score_array_len * sizeof(double));        /* 12/91 GS TLG */
  401. #endif
  402. #endif
  403. }
  404.  
  405. /* for debugging purposes */
  406. void print_document_score_array(start,stop)
  407. unsigned long start;
  408. unsigned long stop;
  409. /* assumes start >= 0, stop < db->doc_table_allocated_entries */
  410. {
  411.     long i;
  412.     for(i = start; i <= stop; i++){
  413.         printf("entry number %d: %f \n", 
  414.                i, document_score_array[i]);
  415.     }
  416. }
  417.  
  418.  
  419.  
  420. /*=========================*
  421.  *===  Best Hits Array  ===*
  422.  *=========================*/
  423.  
  424. hit *best_hits_array = NULL;
  425. long best_hits_array_len = 0;
  426. long current_best_hit = 0;
  427. long doc_start = 0; /* tung, 5/94 */
  428. long doc_end = 0;   /* tung, 5/94 */
  429.  
  430. /* see irext.h for doc */
  431. long init_best_hit (db)
  432.      database *db;
  433. {
  434.  
  435. #ifdef BOOL
  436.   if (currentQuery != NULL)
  437.     send(currentQuery,InitBestHit,db);
  438. #endif /* def BOOL */
  439.  
  440.   return(0);
  441. }
  442.  
  443. /* make_best_hits_array insures that the best_hits_array
  444.    array is long enough, if not it makes it long enough */
  445. static void make_best_hits_array _AP((long length));
  446. static void make_best_hits_array(length)
  447. long length;
  448. {
  449.   if(length <= best_hits_array_len)
  450.     return;
  451.   /* we have to make a new one.  free the old one first (if any) */
  452.   if(best_hits_array != 0){
  453.     s_free(best_hits_array);
  454.   }
  455.   best_hits_array = (hit*)s_malloc((size_t)(length * sizeof(hit)));
  456.   best_hits_array_len = length;
  457. }
  458.  
  459. static void destroy_best_hits_array _AP((void));
  460. static void destroy_best_hits_array()
  461. {
  462.   s_free(best_hits_array);
  463.   best_hits_array_len = 0;
  464. }
  465.     
  466. void clear_best_hits_array()
  467. /* side effects the best_hits_array.  XXX could use memset */
  468.   memset((char*)best_hits_array, 0, best_hits_array_len * sizeof(hit));
  469. }
  470.  
  471. /* for debugging purposes */
  472. void print_best_hits()
  473. {
  474.   long i;
  475.   for( i = 0; i < best_hits_array_len; i++){
  476.     if (best_hits_array[i].weight != 0)
  477.       { printf("Best hit %ld: weight %lf, doc_id %ld, headline %s, filename %s, lines %ld\n", 
  478.            i, best_hits_array[i].weight, 
  479.            best_hits_array[i].document_id,
  480.            best_hits_array[i].headline,
  481.            best_hits_array[i].filename,
  482.            best_hits_array[i].number_of_lines);
  483.       }
  484.   }
  485. }
  486.  
  487. void sort_best_hits(db)
  488.      database * db;
  489. {
  490.   /* returns nothing.
  491.    * side effects best_hits and document_score_array
  492.    */
  493.  
  494.   long i, doc;
  495.   double worst_weight_to_make_it = 0.0;
  496.   document_table_entry doc_entry;
  497.   long best_hit_number = 0;
  498.  
  499.   /* snuff the scores */
  500.   for(i = 0; i < max_hit_retrieved; i++){
  501.     best_hits_array[i].weight = 0.0;
  502.  
  503.   }
  504.  
  505.   /* loop over the doc, and keep the doc_id and weight in best hit table */
  506.   /* for(doc = 0; doc < db->doc_table_allocated_entries; doc++){ */
  507.   for(doc = doc_start; doc <= doc_end; doc++) {
  508.     double weight = document_score_array[doc];
  509.     /* jmf */
  510.     if(weight > 0) {
  511. #ifndef NEW_WEIGHT /* tung, 5/94 */
  512.       read_document_table_entry(&doc_entry, doc, db);  /* if this could be
  513.                               removed, we'd gain speed */
  514.       if (doc_entry.document_length)
  515.     weight/=doc_entry.document_length;
  516.       else
  517.         weight = 0;
  518. #endif
  519.       if(worst_weight_to_make_it < weight){
  520.     /* merge it into the best_hits array. start at the bottom */
  521.     for(i = (max_hit_retrieved - 1); i >= 0; i--){
  522.       if(weight > best_hits_array[i].weight 
  523.          /* && (check_document_id(doc, db) == true) too slow.*/
  524.          ){
  525.         /* move this entry down */    
  526.         if((i + 1) < max_hit_retrieved){
  527.           best_hits_array[i+1].weight = best_hits_array[i].weight;
  528.           best_hits_array[i+1].document_id = best_hits_array[i].document_id;
  529.         }
  530.         best_hits_array[i].document_id = doc;
  531.         best_hits_array[i].weight = weight;
  532.       }
  533.       else
  534.         break;
  535.     }      
  536.       }
  537.     }
  538.   }
  539.   doc_start = doc_end = 0; /* tung, 5/94 */
  540.   for(i = 0; i < max_hit_retrieved; i++){
  541.     if(best_hits_array[i].weight <= 0.0)
  542.       return;
  543.     if (read_document_table_entry(&doc_entry,
  544.                   best_hits_array[i].document_id,
  545.                   db) 
  546.     == true){
  547.       best_hits_array[best_hit_number].weight = best_hits_array[i].weight;
  548.  
  549.       best_hits_array[best_hit_number].document_id = best_hits_array[i].document_id;
  550.       best_hits_array[best_hit_number].start_character = doc_entry.start_character;
  551.       best_hits_array[best_hit_number].end_character = doc_entry.end_character;
  552.       best_hits_array[best_hit_number].document_length = doc_entry.document_length;
  553.       best_hits_array[best_hit_number].number_of_lines = doc_entry.number_of_lines;
  554.       sprintf(best_hits_array[best_hit_number].date, "%d", doc_entry.date);
  555.       read_filename_table_entry(doc_entry.filename_id, 
  556.                 best_hits_array[best_hit_number].filename,
  557.                 best_hits_array[best_hit_number].type,
  558.                 NULL,
  559.                 db),
  560.       strncpy(best_hits_array[best_hit_number].headline, 
  561.           read_headline_table_entry(doc_entry.headline_id,db),
  562.           MAX_HEADLINE_LEN);
  563.       best_hit_number++;
  564.     } 
  565.     beFriendly();
  566.   }
  567.   for(i = best_hit_number; i < max_hit_retrieved; i++){
  568.     best_hits_array[best_hit_number].weight = 0.0;
  569.   }
  570.   /* print_best_hits(s);  for debugging */
  571. }
  572.  
  573.  
  574. /* returns the next best hit */
  575. long best_hit(db, doc_id, best_character, best_line, score,start,end,date,
  576. length,nlines,headline,filename,type)
  577.      database *db;
  578.      long *doc_id;    
  579.      long *best_character;
  580.      long *best_line;
  581.      double *score;
  582.     long *start,*end,*date,*length,*nlines;
  583. char *headline,*filename,*type;
  584. {
  585. double tmp;
  586.  
  587.   *best_character = 0; 
  588.   *best_line = 0;
  589.   
  590. #ifdef BOOL
  591.   if (currentQuery != NULL) /* for boolean */
  592.    {
  593.      send(currentQuery,GetBestHit,db,doc_id,best_character,best_line,score);
  594.      if (*doc_id > 0)
  595.        return(0); /* ok */
  596.      else
  597.        return(-1); /* no more docs */
  598.    }
  599. #endif /* BOOL */
  600.  
  601.   if(current_best_hit > best_hits_array_len)
  602.     return(1);
  603.   if(best_hits_array[current_best_hit].weight == 0.0)
  604.     return(1);
  605.   *doc_id = best_hits_array[current_best_hit].document_id;
  606.   tmp  = ((double)(best_hits_array[current_best_hit].weight*VALUE));
  607. *score=tmp;
  608. *start=best_hits_array[current_best_hit].start_character;
  609. *end=best_hits_array[current_best_hit].end_character;
  610. *date=atol(best_hits_array[current_best_hit].date);
  611. *length=best_hits_array[current_best_hit].document_length;
  612. *nlines=best_hits_array[current_best_hit].number_of_lines;
  613. strcpy(headline,best_hits_array[current_best_hit].headline);
  614. strcpy(filename,best_hits_array[current_best_hit].filename);
  615. strcpy(type,best_hits_array[current_best_hit].type);
  616.   current_best_hit++;
  617.   return(0);
  618. }
  619.  
  620. long finished_best_hit(db)
  621. database *db;
  622.  
  623. #ifdef BOOL
  624.   if (currentQuery != NULL) /* for boolean */
  625.    { send(currentQuery,Delete);
  626.      currentQuery = NULL;
  627.      return(0);
  628.    }
  629. #endif /* BOOL */
  630.  
  631.   /* if we are on a small machine, we might want to 
  632.      destroy_document_score_array */
  633.   clear_document_score_array();
  634.   clear_best_hits_array();
  635.   current_best_hit = 0;
  636.   return(0);
  637. }
  638.  
  639. /*=============================*    
  640.  *===  Searching for words  ===*
  641.  *=============================*/
  642.  
  643. /* see irext.h for doc */
  644. long init_search_word (db)
  645.      database* db;
  646. {
  647. char fn[256];
  648.   strcpy( fn,db->database_file );
  649.   strcat( fn,synonym_ext );
  650.   syn_ReadFile( fn,&db->syn_Table,&db->syn_Table_Size );
  651.  
  652.   return(0);
  653. }
  654.  
  655. #ifdef NESTED_BOOLEANS
  656. /* tung, 10/93 */
  657. extern long number_of_operands ;
  658. /* tung, 10/93 */
  659. #endif
  660.  
  661. #ifdef BOOLEANS
  662. static boolean   gLastAnd= false;
  663. static boolean   gLastNot= false;
  664. #endif
  665.  
  666. /* see irext.h for doc */
  667. long search_word(word,
  668. #ifdef FIELDS /* tung, 5/94 */
  669.          field_name,
  670. #endif
  671.          char_pos, line_pos, weight, doc_id, 
  672.          word_pair, db)
  673.      char *word; /* the word to be searched for */
  674. #ifdef FIELDS /* tung, 5/94 */
  675.      char *field_name;
  676. #endif
  677.      long char_pos;        /* the position of the start of the word */
  678.      long line_pos;        /* is this needed? not for signature system */
  679.      long weight;        /* how important the word looks syntactically,
  680.                    such as is it bold */
  681.      long doc_id;        /* current document, seed words is 0,
  682.                    then it increments into the relevant 
  683.                    document */
  684.      long word_pair;
  685.      database *db;
  686. {
  687.   /* this side effects the document_score_array,
  688.    * and downcases the word.
  689.    * Returns 0 if successful or word not present, 
  690.    * returns non-0 if an error.
  691.    *
  692.    */
  693.   
  694.   long not_full_flag = INDEX_BLOCK_FULL_FLAG; /* start out full so it will go on looking */
  695.   long count, index_block_size;
  696.   long internal_document_id,  number_of_valid_entries;
  697.   double internal_weight;
  698.   long index_file_block_number;
  699.   long number_of_occurances;
  700.  
  701.   FOUR_BYTE index_buffer_data[INDEX_ELEMENT_SIZE*(1024/4)];
  702.   char *index_buffer;
  703. #ifdef undef
  704.   char *i = index_buffer;       /* What the hell should be in i ? (up) */
  705. #endif
  706.   FILE *stream = NULL;
  707.  
  708.  
  709. #ifdef LITERAL
  710.   long txt_pos, icnt, wcnt, pcnt;                    /* 2/92 GS TLG */
  711.   document_table_entry doc_entry;                    /* 2/92 GS TLG */
  712.   static FILE *txt_stream = NULL;                    /* 2/92 GS TLG */
  713.   char cmpr_word[MAX_PHRASE_LENGTH + 1];                /* 2/92 GS TLG */
  714.   /*char phrase[MAX_PHRASE_LENGTH + 1];    */                /* 2/92 GS TLG */
  715.   char txt_filename[MAX_FILENAME_LEN + 1];                /* 2/92 GS TLG */
  716.   char *temp_txt_filename = NULL;                    /* francois */
  717.   char prev_txt_filename[MAX_FILENAME_LEN + 1];                /* 2/92 GS TLG */
  718.   char txt_type[MAX_TYPE_LEN + 1];                    /* 2/92 GS TLG */
  719.   long phraselen= 0, txt_pos_fix= 0;
  720.   char *document_section = NULL;     /* tung , 10/93 */
  721.   long document_section_len = 0;     /* tung , 10/93 */
  722.   long phrase_readed = 0;            /* tung , 10/93 */
  723.   long phrase_count = 0;             /* tung , 10/93 */
  724.   boolean phrase_found = false;      /* tung , 10/93 */
  725. #endif
  726.  
  727. #ifdef NESTED_BOOLEANS /* tung, 10/93 */
  728.   long numeric_partial_valid_entries = 0;
  729. #endif
  730.  
  731. #ifdef NEW_WEIGHT /* tung, 5/94 */
  732.   double query_wgt;
  733. #else
  734.   double idf;
  735. #endif
  736. #ifdef FIELDS /* tung, 12/93 */
  737.   long field_id = -1;
  738.   boolean SearchField = false;
  739. #endif
  740.  
  741.   /* do synonym conversion */
  742.   
  743.   /* in theory, one can replace a word with a boolean phrase */
  744.   char *newword;
  745.  
  746.   newword = lookup_Synonym( word,db->syn_Table,db->syn_Table_Size );
  747.   waislog(WLOG_HIGH,WLOG_INFO,"Word %s Syn %s",word,newword);
  748.   strncpy(word,newword,MAX_WORD_LENGTH);
  749.  
  750. #ifdef FIELDS /* tung, 12/93 */
  751.   if(db->number_of_fields > 0) {
  752.     if(*field_name != '\0') {
  753.       if(strcmp(field_name, FREE_TEXT_FIELD) == 0) { /* global database */
  754.     field_name = "\0";
  755.         SearchField = false;
  756.     field_id = -1;
  757.       } else { 
  758.     SearchField = true;
  759.     field_id = pick_up_field_id(field_name, db);
  760.       }
  761.     }
  762.   }
  763. #endif
  764.   
  765. /* tung, 10/93 */
  766. #ifdef NESTED_BOOLEANS
  767.   if(number_of_operands > 1) {
  768.     make_search_result_array(number_of_operands);
  769.     if((weight!=LITERAL_FLAG) && IsOperator(word)) {
  770.       boolean_operations(word, search_result_array);
  771.       return(0);
  772.     }
  773.     if(strlen(word) == 1) {
  774.       search_result_array[operand_id].number_of_hits = 0;
  775.       search_result_array[operand_id].operand_id = operand_id;
  776.       if(!save_operand_id(operand_id, search_result_array, db->doc_table_allocated_entries))
  777.     return(-1);
  778.       ++operand_id;
  779.       return(0);
  780.     }
  781.   }
  782. #endif
  783. /* tung, 10/93 */
  784.  
  785.   /* francois - call the stemmer */
  786. #ifdef FIELDS /* tung, 1/94 */
  787.   if(weight!=LITERAL_FLAG &&  weight!= FIELD_FLAG && weight!= NUMERIC_FLAG) {
  788. #ifdef STEM_WORDS
  789.     if(field_id > -1) {
  790.       if(db->fields[field_id].stemming)
  791.     stemmer(word);  
  792.     }
  793.     else {
  794.       if(db->stemming)
  795.     stemmer(word);
  796.     }
  797. #endif
  798.   }
  799. #else
  800. #ifdef LITERAL
  801.   if (weight!=LITERAL_FLAG) {
  802.     stemmer(word); 
  803.   }
  804. #else
  805.   stemmer(word); 
  806. #endif
  807. #endif
  808.  
  809. #ifdef LITERAL
  810.   if (weight==LITERAL_FLAG) {
  811.     /* goto after_booleans */
  812. /* printf("search_word: literal word is [%s]\n", word); */
  813.     }
  814.   else 
  815. #endif
  816.  
  817. #ifndef NESTED_BOOLEANS /* 10,93 */
  818. #ifdef BOOLEANS
  819.   if (strcmp(word,BOOLEAN_AND)==0) {  /* should be all lowercase cmp here */
  820.     gLastAnd= true;
  821.     return(0);
  822.     }
  823.   else if (strcmp(word,BOOLEAN_NOT)==0) {  
  824.   /* ^^ this is bad if we intersperse "not"s in a query --
  825.      docs found after not word may include notted word --
  826.      need to go back to doing not words after others --
  827.      but need now to check for literal string first
  828.   */
  829.     gLastNot= true;
  830.     return(0);
  831.   }
  832.   if (weight == BOOLEAN_NOT_FLAG) gLastNot= true;
  833. #else
  834.      ;   /* if not LITERAL_FLAG */
  835. #endif
  836. #endif /* #ifndef NESTED_BOOLEANS */
  837.  
  838.   index_buffer = (char*)index_buffer_data;
  839.  
  840. #ifdef LITERAL
  841.   if (weight==LITERAL_FLAG) {
  842.   /* note: we found the first word of phrase once in map_over_words, but i'm too lazy 
  843.       to put another parameter in that cascade of function calls it takes
  844.     to get here.
  845.   */
  846.     char  word1[MAX_WORD_LENGTH + 1];
  847.     register int i, len;
  848.     register boolean more;
  849.     phraselen= MINIMUM( MAX_PHRASE_LENGTH, strlen(word));
  850.     len = MINIMUM( MAX_WORD_LENGTH, phraselen);
  851.     for (i=0, more=true; i < len && more; ) {
  852.       word1[i] = word[i++];
  853. #ifdef BIO
  854.       more= (wordDelimiter(word[i]) == NOT_DELIMITER); 
  855. #else
  856.       more= (isalnum(word[i]));
  857. #endif
  858.      }
  859.     word1[i]= '\0';
  860.     txt_pos_fix= strlen(word1) + 1;
  861. /* printf("search_word: literal word1 is [%s]\n", word1); */
  862. #ifdef FIELDS /* tung, 1/94 */
  863.     if((db->number_of_fields == 0) && !SearchField)
  864.       index_file_block_number = 
  865.         look_up_word_in_dictionary(word1, &number_of_occurances, db);
  866.     else 
  867.       index_file_block_number = 
  868.         field_look_up_word_in_dictionary(field_name, word1, &number_of_occurances, db);
  869. #else
  870.     index_file_block_number = 
  871.       look_up_word_in_dictionary(word1, &number_of_occurances, db);
  872. #endif
  873.   }
  874.   else
  875. #endif  /* LITERAL */
  876.  
  877. #ifdef PARTIALWORD
  878. #ifdef FIELDS /* tung, 1/94 */
  879.     index_file_block_number = 
  880.       look_up_partialword_in_dictionary(field_name, 
  881.                                         word, &number_of_occurances, db);
  882. #else
  883.     index_file_block_number = 
  884.       look_up_partialword_in_dictionary(word, &number_of_occurances, db);
  885. #endif
  886. #else
  887.   index_file_block_number = 
  888.     look_up_word_in_dictionary(word, &number_of_occurances, db);
  889. #endif
  890.  
  891.   current_best_hit = 0;  /* so that the best hits willstart from 0 */
  892.  
  893.   /* check the document_score_array */
  894.   if(document_score_array_len < db->doc_table_allocated_entries)
  895.     make_document_score_array(db->doc_table_allocated_entries);
  896.  
  897.   if(index_file_block_number >= 0){
  898. #ifdef PARTIALWORD
  899.    while(index_file_block_number > 0){  /* dgg, need 2nd loop here for multiple partwords */
  900. #endif
  901.  
  902. #ifdef FIELDS /* tung, 1/94 */
  903.      if(SearchField && *field_name != '\0') 
  904.        stream = db->field_index_streams[pick_up_field_id(field_name, db)];
  905.      else stream = db->index_stream;
  906. #else
  907.      stream = db->index_stream;
  908. #endif
  909.  
  910.     while((not_full_flag != INDEX_BLOCK_NOT_FULL_FLAG) && 
  911.       (index_file_block_number != 0)){    
  912.       /* read the index block */
  913.       if (0 != fseek(stream, (long)index_file_block_number, 
  914.              SEEK_SET))    
  915.     { 
  916.       waislog(WLOG_HIGH, WLOG_ERROR, 
  917.           "fseek failed into the inverted file to position %ld",
  918.           (long)index_file_block_number); 
  919. #ifdef BOOLEANS
  920.    gLastNot= gLastAnd= false;
  921. #endif  
  922.       return(-1);
  923.     }
  924. /*      
  925.       read(fileno(stream),index_buffer,INDEX_BLOCK_HEADER_SIZE);
  926.  
  927.       ASSIGN(not_full_flag,
  928.          INDEX_BLOCK_FLAG_SIZE,
  929.          index_buffer,
  930.          INDEX_BLOCK_HEADER_SIZE,
  931.          0 );
  932.       ASSIGN(index_file_block_number,NEXT_INDEX_BLOCK_SIZE,
  933.          index_buffer+INDEX_BLOCK_FLAG_SIZE,
  934.          INDEX_BLOCK_HEADER_SIZE,
  935.          INDEX_BLOCK_FLAG_SIZE);
  936.       ASSIGN(index_block_size,INDEX_BLOCK_SIZE_SIZE,
  937.          index_buffer+INDEX_BLOCK_FLAG_SIZE+NEXT_INDEX_BLOCK_SIZE,
  938.          INDEX_BLOCK_HEADER_SIZE,
  939.          INDEX_BLOCK_FLAG_SIZE+NEXT_INDEX_BLOCK_SIZE);
  940.  
  941.   this is equivalent, but slower:
  942. */
  943.       not_full_flag = read_bytes(INDEX_BLOCK_FLAG_SIZE, stream);
  944.       index_file_block_number = read_bytes(NEXT_INDEX_BLOCK_SIZE, stream);
  945.       index_block_size = read_bytes(INDEX_BLOCK_SIZE_SIZE, stream);
  946.  
  947. /*  Jim's debug code commented out
  948.       printf("flag = %d, block_num = %d, block_size = %d\n",
  949.          not_full_flag, 
  950.          index_file_block_number,
  951.          index_block_size);
  952. */
  953.       fflush(stdout);
  954.  
  955.       if(EOF == index_block_size) 
  956.     { 
  957.       waislog(WLOG_HIGH, WLOG_ERROR, 
  958.           "reading from the index file failed");
  959. #ifdef BOOLEANS
  960.    gLastNot= gLastAnd= false;
  961. #endif  
  962.       return(-1);
  963.     }
  964.       
  965.       if(not_full_flag == INDEX_BLOCK_NOT_FULL_FLAG){
  966.     /* not full */
  967.     number_of_valid_entries = index_file_block_number;
  968.       }
  969.       else if(not_full_flag == INDEX_BLOCK_FULL_FLAG){
  970.     /* full */
  971.     number_of_valid_entries = index_block_size - INDEX_BLOCK_HEADER_SIZE;
  972.       }
  973.       else{            /* bad news, file is corrupted. */
  974.     waislog(WLOG_HIGH, WLOG_ERROR, 
  975.         "Expected the flag in the inverted file to be valid.  it is %ld",
  976.         not_full_flag);
  977. #ifdef BOOLEANS
  978.    gLastNot= gLastAnd= false;
  979. #endif  
  980.     return(-1);
  981.       }
  982.       /* printf("number of valid bytes: %ld\n", number_of_valid_entries); */
  983.       
  984.       /* add the array to the document_score_array */
  985.       number_of_valid_entries /= INDEX_ELEMENT_SIZE;
  986.  
  987. /* tung, 10/93 */
  988. #ifdef NESTED_BOOLEANS   
  989.       if((number_of_operands > 1) && (search_result_array != NULL)) {
  990. #ifdef FIELDS /* tung, 1/94 */
  991.         if(weight != NUMERIC_FLAG && weight != PARTIAL_FLAG) {
  992. #else
  993.         if(weight != PARTIAL_FLAG) {
  994. #endif
  995.           if(!make_doc_ids_array(operand_id, db->doc_table_allocated_entries))
  996.         return(-1);
  997.           search_result_array[operand_id].number_of_hits = number_of_valid_entries;
  998.         }
  999.       }
  1000. #endif
  1001. /* tung, 10/93 */
  1002.  
  1003. #ifdef NEW_WEIGHT /* tung, 5/94 */      
  1004.     query_wgt = 1;
  1005. #else
  1006.     /* ses - idf is a fist approximation to the inverse document freq. */
  1007.     /* what it actually is  is the inverse occurance frequency which says
  1008.      * that the significance of a word is inversly proportional to the number
  1009.      * of times it occurs in the database */
  1010.  
  1011.     idf=1.0/number_of_occurances; 
  1012. #endif
  1013.       for(count=0;count <  number_of_valid_entries;count++) {
  1014.     int wgt;
  1015.     int did;
  1016. /*
  1017.     if(count%1024 == 0) {
  1018.       read(fileno(stream),index_buffer,INDEX_ELEMENT_SIZE*
  1019.         MINIMUM(1024,number_of_valid_entries-count));
  1020.       i=index_buffer;
  1021.     }
  1022. */
  1023.     did = read_bytes(DOCUMENT_ID_SIZE, stream);
  1024.         (void)read_bytes(WORD_POSITION_SIZE, stream);
  1025.         txt_pos=read_bytes(CHARACTER_POSITION_SIZE, stream);
  1026.         wgt = read_bytes(WEIGHT_SIZE,stream);
  1027. #ifdef NEW_WEIGHT /* tung, 5/94 */
  1028.     internal_weight = read_weight_from_stream(NEW_WEIGHT_SIZE, stream);
  1029. #endif
  1030. /*
  1031.  
  1032.     ASSIGN(wgt,WEIGHT_SIZE,    
  1033.            i+DOCUMENT_ID_SIZE+WORD_POSITION_SIZE+CHARACTER_POSITION_SIZE,
  1034.            INDEX_ELEMENT_SIZE,
  1035.            DOCUMENT_ID_SIZE+WORD_POSITION_SIZE+CHARACTER_POSITION_SIZE);
  1036.     ASSIGN(did,DOCUMENT_ID_SIZE,i,INDEX_ELEMENT_SIZE,0);
  1037. */
  1038. #ifdef LITERAL
  1039.     /* dgg -- is this proper update of read form to ASSIGN form ??*/
  1040.     /* txt_pos = read_bytes(CHARACTER_POSITION_SIZE, stream);*/        /* 2/92 GS TLG */
  1041.         if ((weight == LITERAL_FLAG) && (0 == doc_id))  {         
  1042. /*
  1043.     ASSIGN(txt_pos,CHARACTER_POSITION_SIZE,i+DOCUMENT_ID_SIZE+WORD_POSITION_SIZE,
  1044.         INDEX_ELEMENT_SIZE,DOCUMENT_ID_SIZE+WORD_POSITION_SIZE);
  1045. */
  1046. /* printf("search_word: txtpos=%d, wgt=%d, did=%d\n", txt_pos, wgt, did); */
  1047.         }
  1048. #endif
  1049.  
  1050. /* Commented out as suggested by Stan Isaacs at hp.com to come up with correct
  1051.  * weights when there are multiple documents in a file
  1052.  *
  1053.  *    if(wgt>5L)
  1054.  *        wgt-=5L;
  1055.  */
  1056. #ifndef NEW_WEIGHT /* tung, 5/94 */
  1057.     internal_weight = log((double)wgt);
  1058.     internal_weight+=10.0;
  1059. #endif
  1060.     internal_document_id = did;
  1061.     if((doc_start == 0) && (doc_end == 0)) /* tung, 5/94 */
  1062.       doc_start = doc_end = did;           /* tung, 5/94 */
  1063.     doc_start = MINIMUM(doc_start, did);   /* tung, 5/94 */
  1064.     doc_end = MAXIMUM(doc_end, did);       /* tung, 5/94 */
  1065.  
  1066. /*
  1067.     printf("entry %ld, Doc_id: %ld, weight %lf \n",
  1068.         count, internal_document_id, internal_weight);
  1069.     fflush(stdout);
  1070. */
  1071.     if(EOF == wgt) 
  1072.       { 
  1073.         waislog(WLOG_HIGH, WLOG_ERROR, 
  1074.             "reading from the doc-id table failed");
  1075. #ifdef BOOLEANS
  1076.    gLastNot= gLastAnd= false;
  1077. #endif  
  1078.         return(-1);
  1079.       }
  1080.  
  1081. #ifdef LITERAL         
  1082.         if ((weight == LITERAL_FLAG) && (0 == doc_id)) {        /* 2/92 GS TLG */
  1083.           if (true == read_document_table_entry(&doc_entry,        /* 2/92 GS TLG */
  1084.                                              internal_document_id, db)) /* 2/92 GS TLG */
  1085.        {                                /* 2/92 GS TLG */
  1086.             read_filename_table_entry(doc_entry.filename_id,        /* 2/92 GS TLG */
  1087.                                       txt_filename, txt_type, NULL, db);  /* 2/92 GS TLG */
  1088. /* printf("search_word: document is [%s]\n", txt_filename); */
  1089.             if (NULL == txt_stream) {
  1090.               /* francois */
  1091.               if (probe_file(txt_filename)) {
  1092.                 txt_stream = s_fopen(txt_filename, "rb");
  1093.               }
  1094.               else if (probe_file_possibly_compressed(txt_filename)) {
  1095.                temp_txt_filename = s_fzcat(txt_filename);
  1096.                if (temp_txt_filename) {
  1097.              txt_stream = s_fopen(temp_txt_filename, "rb");
  1098.             }
  1099.            }
  1100.            
  1101.               strcpy(prev_txt_filename, txt_filename);
  1102.              }
  1103.             else if (0 != strcmp(txt_filename, prev_txt_filename)) {
  1104.               s_fclose(txt_stream);
  1105.               /* francois */
  1106.               if ( temp_txt_filename != NULL ) {
  1107.                 unlink(temp_txt_filename);
  1108.                 s_free(temp_txt_filename);
  1109.               }
  1110.               if (probe_file(txt_filename)) {
  1111.                 txt_stream = s_fopen(txt_filename, "rb");
  1112.               }
  1113.               else if (probe_file_possibly_compressed(txt_filename)) {
  1114.                temp_txt_filename = s_fzcat(txt_filename);
  1115.                if (temp_txt_filename) {
  1116.              txt_stream = s_fopen(temp_txt_filename, "rb");
  1117.              }
  1118.            }
  1119.               strcpy(prev_txt_filename, txt_filename);        /* 2/92 GS TLG */
  1120.               }
  1121.  
  1122.             txt_pos += doc_entry.start_character - txt_pos_fix;  /* dgg */
  1123.             document_section_len = doc_entry.end_character - txt_pos;   /* tung, 10/93 */
  1124.             s_fseek(txt_stream, txt_pos, SEEK_SET);            /* 2/92 GS TLG */
  1125.             document_section = 
  1126.               (char*) s_malloc((size_t)((document_section_len+1)*sizeof(char))); /* tung, 10/93 */
  1127.             fgets(document_section, document_section_len, txt_stream);   /* tung, 10/93 */
  1128.             phrase_readed = 0;                                           /* tung, 10/93 */
  1129.             phrase_readed += strlen(document_section);                   /* tung, 10/93 */
  1130.             document_section = string_downcase(document_section);        /* tung, 10/93 */
  1131. #if 0
  1132.             fread(phrase, 1L, phraselen, txt_stream);            /* 2/92 GS TLG */
  1133.             /* { phrase[phraselen]= '\0';
  1134.                printf("search_word: file phrase is [%s]\n", phrase); 
  1135.                } */
  1136.             if (0 != strncasecmp(word, phrase, phraselen))        /* 2/92 GS TLG */
  1137.               internal_weight = 0.0;                                    /* 2/92 GS TLG */
  1138. #endif                
  1139.             if (NULL == strstr(document_section, word)) {                    /* tung, 10/93 */
  1140.               while(phrase_readed < document_section_len) {                  /* tung, 10/93 */
  1141.                 fgets(document_section, document_section_len, txt_stream);   /* tung, 10/93 */
  1142.                 phrase_readed += strlen(document_section);                   /* tung, 10/93 */
  1143.                 document_section = string_downcase(document_section);        /* tung, 10/93 */
  1144.                 if(strstr(document_section, word) != NULL)  {                /* tung, 10/93 */
  1145.                   phrase_found = true;                                       /* tung, 10/93 */
  1146.                   break;                                                     /* tung, 10/93 */
  1147.                 }                                                            /* tung, 10/93 */
  1148.               }                                                              /* tung, 10/93 */
  1149.               if(phrase_found == false)                                      /* tung, 10/93 */
  1150.                 internal_weight = 0.0;                         /* tung, 10/93 */
  1151.               phrase_found = false;                                          /* tung, 10/93 */
  1152.             } 
  1153.             s_free(document_section);                                        /* tung, 10/93 */
  1154.           }
  1155.         }                                
  1156. #endif
  1157.  
  1158. #ifndef NESTED_BOOLEANS /* 10,93 */
  1159. #ifdef BOOLEANS
  1160.     if (gLastNot) {    
  1161.        document_score_array[internal_document_id] = 0;
  1162. /*     printf("search_word: boolean 'not' scored\n"); */
  1163.         }
  1164.         else 
  1165. #endif
  1166. #endif /* #ifndef NESTED_BOOLEANS */
  1167.     {
  1168.     /* if(doc_id > 0) we are doing a relevant document */
  1169. /*
  1170. printf("wgt: %ld, internal weight: %lf, idf: %lf occurances: %ld\n",
  1171.     wgt,internal_weight, idf,number_of_occurances);
  1172. fflush(stdout);
  1173. */
  1174. #ifndef NEW_WEIGHT /* tung, 5/94 */
  1175.         internal_weight*=idf; /* ses - for inverse doc. freq. */
  1176. #endif
  1177. #ifndef NESTED_BOOLEANS
  1178. #ifdef NEW_WEIGHT /* tung, 5/94 */
  1179.     document_score_array[internal_document_id] += 
  1180.       (query_wgt *  internal_weight);
  1181. #else
  1182.     document_score_array[internal_document_id] += 
  1183.       (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  1184. #endif
  1185. #else
  1186. /* tung, 10/93 */
  1187.         if(number_of_operands == 1) {
  1188. #ifdef NEW_WEIGHT /* tung, 5/94 */
  1189.       document_score_array[internal_document_id] += 
  1190.         (query_wgt *  internal_weight);
  1191. #else
  1192.           document_score_array[internal_document_id] += 
  1193.         (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  1194. #endif
  1195.         }
  1196.         else {
  1197.           if((number_of_operands > 1) && (search_result_array != NULL)) {
  1198.             if(weight == LITERAL_FLAG) {
  1199. #ifdef NEW_WEIGHT /* tung, 5/94 */
  1200.           ((search_result_array[operand_id]).doc_ids_array[phrase_count]).score +=
  1201.         (query_wgt *  internal_weight);
  1202. #else
  1203.               ((search_result_array[operand_id]).doc_ids_array[phrase_count]).score +=
  1204.                 (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  1205. #endif
  1206.               if(((search_result_array[operand_id]).doc_ids_array[phrase_count]).score > 0) {
  1207.                 ((search_result_array[operand_id]).doc_ids_array[phrase_count]).doc_id = internal_document_id;
  1208.                 phrase_count++;
  1209.                 search_result_array[operand_id].number_of_hits = phrase_count;
  1210.               }
  1211.             }
  1212. #ifdef FIELDS /* tung, 1/94 */
  1213.             else if(weight == NUMERIC_FLAG || weight == PARTIAL_FLAG) {
  1214. #else
  1215.             else if(weight == PARTIAL_FLAG) {
  1216. #endif
  1217.               if(NumPart_score_array[internal_document_id] <= 0)
  1218.                 ++numeric_partial_valid_entries;
  1219. #ifdef NEW_WEIGHT /* tung, 5/94 */
  1220.           NumPart_score_array[internal_document_id] = 
  1221.         MAXIMUM(NumPart_score_array[internal_document_id], (query_wgt *  internal_weight));
  1222. #else
  1223.               NumPart_score_array[internal_document_id] += 
  1224.                 (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  1225. #endif
  1226.             }
  1227.             else {
  1228.               ((search_result_array[operand_id]).doc_ids_array[count]).doc_id = internal_document_id;
  1229. #ifdef NEW_WEIGHT /* tung, 5/94 */
  1230.           ((search_result_array[operand_id]).doc_ids_array[count]).score +=
  1231.         (query_wgt *  internal_weight);
  1232. #else
  1233.               ((search_result_array[operand_id]).doc_ids_array[count]).score +=
  1234.                 (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  1235. #endif
  1236.             }
  1237.           }
  1238.         }
  1239. #endif
  1240. /* tung, 10/93 */
  1241.         
  1242.       }
  1243. /*
  1244. printf("Score array: %lf\n",document_score_array[internal_document_id]);
  1245. fflush(stdout);
  1246. */
  1247.  
  1248.     /* i+=INDEX_ELEMENT_SIZE;  Purify (umr): uninitialized memory read: (up) */
  1249.       }
  1250.     }
  1251.  
  1252. #ifdef PARTIALWORD
  1253. #ifdef FIELDS /* tung, 1/94 */
  1254.   index_file_block_number = 
  1255.     look_up_partialword_in_dictionary(field_name, 
  1256.                                       NULL, &number_of_occurances, db);
  1257. #else
  1258.   index_file_block_number = 
  1259.     look_up_partialword_in_dictionary(NULL, &number_of_occurances, db);
  1260. #endif      
  1261.   }
  1262. #endif
  1263.  
  1264. #ifdef NESTED_BOOLEANS /* tung, 1/94 */
  1265.    if(number_of_operands > 1) {
  1266.      long index = 0;
  1267. #ifdef FIELDS /* tung, 1/94 */
  1268.      if(weight == NUMERIC_FLAG || weight == PARTIAL_FLAG) {
  1269. #else
  1270.      if(weight == PARTIAL_FLAG) {
  1271. #endif
  1272.        if(!make_doc_ids_array(operand_id, db->doc_table_allocated_entries))
  1273.      return(-1);
  1274.        search_result_array[operand_id].number_of_hits =
  1275.          numeric_partial_valid_entries;
  1276.        /*for (count=0; count < db->doc_table_allocated_entries; count++) {*/
  1277.        for (count=doc_start; count <= doc_end ; count++) {
  1278.          if(NumPart_score_array[count] > 0) {
  1279.            ((search_result_array[operand_id]).doc_ids_array[index]).doc_id = count;
  1280.            ((search_result_array[operand_id]).doc_ids_array[index]).score
  1281.              = NumPart_score_array[count];
  1282.            NumPart_score_array[count] = 0.0;
  1283.            ++index;
  1284.          }
  1285.          if(index == numeric_partial_valid_entries)
  1286.            break;
  1287.        }
  1288.      }
  1289.    }
  1290. #endif
  1291.  
  1292. /* tung, 10/93 */
  1293. #ifdef NESTED_BOOLEANS
  1294.     if((number_of_operands > 1) && (search_result_array != NULL)) {
  1295.       if(!save_operand_id(operand_id, search_result_array,db->doc_table_allocated_entries))
  1296.     return(-1);
  1297.       search_result_array[operand_id].operand_id = operand_id;
  1298.       ++operand_id;
  1299.     }
  1300. #endif 
  1301. /* tung, 10/93 */
  1302.  
  1303. #ifndef NESTED_BOOLEANS /* tung, 10/94 */
  1304. #ifdef BOOLEANS
  1305.    for (count=0; count < db->doc_table_allocated_entries; count++) {   /* 12/91 GS TLG */
  1306.      if (!gLastAnd) {                             /* 12/91 GS TLG */
  1307.        prev_score_array[count] = document_score_array[count];        /* 12/91 GS TLG */
  1308.      }                                 /* 12/91 GS TLG */
  1309.      else {                                   /* 12/91 GS TLG */
  1310.        if ((document_score_array[count] == prev_score_array[count])    /* 12/91 GS TLG */
  1311.            || (prev_score_array[count] == 0)) {
  1312.          document_score_array[count] = 0;                /* 12/91 GS TLG */
  1313.          prev_score_array[count] = 0;                    /* 12/91 GS TLG */
  1314.        }                                /* 12/91 GS TLG */
  1315.        else {  
  1316.          prev_score_array[count] = document_score_array[count];    /* 12/91 GS TLG */
  1317.        }                                /* 12/91 GS TLG */
  1318.      }                                    /* 12/91 GS TLG */
  1319.    }                                    /* 12/91 GS TLG */
  1320. /*  if (gLastAnd) printf("search_word: boolean `and' scored\n"); */
  1321. #endif
  1322. #endif 
  1323.  
  1324. #ifdef BOOLEANS
  1325.    gLastNot= gLastAnd= false;
  1326. #endif /* BOOLEANS */
  1327.     return(0); 
  1328.   }
  1329.   
  1330.   else if(0 == index_file_block_number){
  1331.     /* an error occurred on looking up the word */
  1332. #ifdef BOOLEANS
  1333.    gLastNot= gLastAnd= false;
  1334. #endif 
  1335.    return(-1);
  1336.  }
  1337.   
  1338.   else {                /* index_file_block_number is negative */
  1339. #ifdef NESTED_BOOLEANS /* tung, 10/93 */
  1340.     if((number_of_operands > 1) && (search_result_array != NULL)) {
  1341.       if(!save_operand_id(operand_id, search_result_array,db->doc_table_allocated_entries))
  1342.     return(-1);
  1343.       search_result_array[operand_id].operand_id = operand_id;
  1344.       search_result_array[operand_id].number_of_hits = 0;
  1345.       ++operand_id;
  1346.     }
  1347. #else
  1348. #ifdef BOOLEANS
  1349.     if (gLastAnd) 
  1350.       for (count=0; count < db->doc_table_allocated_entries; count++) {
  1351.         document_score_array[count] = 0;                       
  1352.         prev_score_array[count] = 0;   
  1353.       } 
  1354.     gLastNot= gLastAnd= false;
  1355. #endif
  1356. #endif 
  1357.     return(0);        /* word not present */
  1358.   }
  1359. }
  1360.  
  1361.  
  1362. /* now collect the best hits */
  1363. long finished_search_word(db)
  1364.      database *db;
  1365. #ifdef NESTED_BOOLEANS
  1366.   long number_of_hits; /* tung, 10/93 */
  1367. #endif
  1368.  
  1369. #ifdef BOOL
  1370.   if (currentQuery != NULL)
  1371.     return; /* do nothing for boolean */
  1372. #endif /* def BOOL */
  1373.  
  1374. /* tung, 10/93 */
  1375. #ifdef NESTED_BOOLEANS
  1376.   if((number_of_operands > 1) && (search_result_array != NULL)) {
  1377.     number_of_hits = retriev_result(db->doc_table_allocated_entries, 
  1378.                                     document_score_array);
  1379.     clear_search_result_array(&number_of_operands);
  1380.   }
  1381. #endif
  1382. /* tung, 10/93 */
  1383.   
  1384.   /* check the document_score_array */
  1385.   if(document_score_array_len < db->doc_table_allocated_entries)
  1386.     make_document_score_array(db->doc_table_allocated_entries);
  1387.  
  1388.   make_best_hits_array(max_hit_retrieved);
  1389.   sort_best_hits(db);
  1390.   syn_Free( db->syn_Table,&db->syn_Table_Size );
  1391.  
  1392.   return(0);
  1393. }
  1394.  
  1395.